package cn.seaboot.admin.user.service;

import cn.seaboot.admin.mvc.cache.CacheName;
import cn.seaboot.admin.mvc.Result;
import cn.seaboot.admin.user.bean.Permit;
import cn.seaboot.admin.user.context.AuthorityCache;
import cn.seaboot.admin.user.context.UserContext;
import cn.seaboot.admin.user.dao.PermitDao;
import cn.seaboot.commons.core.CommonUtils;
import cn.seaboot.commons.core.SmartText;
import cn.seaboot.commons.exception.BizException;
import org.jetbrains.annotations.NotNull;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * @author postm
 */
@Service
public class PermitService {

    @Resource
    private PermitDao permitDao;

    @Resource
    private RolePermitService rolePermitService;

    @Resource
    private UserContext userContext;

    @Resource
    private AuthorityCache<?, ?> authorityCache;


    /**
     * 新增1个空菜单，必填项只有menu的Pid，哪怕其它成员变量menu有值
     *
     * @param roleId 角色ID，通常是当前登录角色，新建的菜单权限会直接赋予到该角色
     * @param pid    菜单父级节点
     * @return SysMenu
     */
    @Transactional(rollbackFor = Exception.class)
    public Permit insert(String roleId, @NotNull String pid) {
        Permit p = permitDao.selectById(pid);
        String idCode = this.getNextPathCode(pid);
        Permit permit = new Permit();
        permit.setId(idCode);
        permit.setPid(pid);
        permit.setPath(idCode);
        permit.setLevel(p.getLevel() + 1);
        permit.setLabel("new node");
        permit.setAuthorityCode(idCode);
        permitDao.insert(permit);

        rolePermitService.insert(roleId, permit.getAuthorityCode());
        return permit;
    }

    /**
     * 菜单编码规则，
     * 例如：根节点为00，第一个子节点则为0001，第二个子节点为0002，
     * 依次类推，每一层最多99个节点。
     *
     * @param pid 父节点ID
     * @return 路径
     */
    private String getNextPathCode(String pid) {
        // 获取最大的子级节点
        String path = permitDao.selectMaxChildrenPath(pid);
        if (CommonUtils.isEmpty(path)) {
            // 如果不存在子级，则定为01编号
            return pid + "01";
        } else {
            int currentValue = Integer.parseInt(path.substring(path.length() - 3));
            if (currentValue == 99) {
                throw new BizException("角色已经达到最大容量，不允许继续增加同级角色！");
            }
            return pid + SmartText.fillZero(1 + currentValue, 2);
        }
    }


    /**
     * 删
     *
     * @param id id
     * @return affected rows
     */
    public int deleteById(String id) {
        Permit permit = permitDao.selectById(id);
        if (permit == null) {
            throw new BizException("权限信息未找到：" + id);
        }
        permitDao.deleteById(id);
        permitDao.deleteChild(permit.getPath());
        rolePermitService.cleanInvalidRolePermit();
        return 1;
    }

    /**
     * 改
     *
     * @param perm pojo
     * @return affected rows
     */
    public int updateSampleById(Permit perm) {
        return permitDao.updateSampleById(perm);
    }

    /**
     * 将权限分配给角色
     *
     * @param ids    权限id
     * @param roleId 角色id
     * @return 不抛出异常就是成功
     */
    @CacheEvict(cacheNames = CacheName.SECURITY, key = "#roleId")
    public Result grantPerm(String roleId, String ids) {
        authorityCache.clear();
        rolePermitService.deleteByRoleId(roleId);
        String[] arr = ids.split(",");
        for (String id : arr) {
            Permit perm = permitDao.selectById(id);
            if (perm == null) {
                throw new BizException("未找到相关权限信息!");
            }
            rolePermitService.insert(roleId, perm.getAuthorityCode());
        }
        return Result.succeed();
    }

    /**
     * 与当前系统全部权限对比，查找可分配的权限
     *
     * @param roleId 目标用户
     * @return 可分配的权限列表
     */
    public List<Permit> selectPermitByRoleId(String roleId) {
        return permitDao.selectPermitByRoleId(roleId);
    }

    /**
     * 查询某个角色所拥有的权限
     *
     * @param roleId 角色 ID
     * @return list
     */
    public Set<String> queryPermitAuthority(String roleId) {
        List<String> perms = permitDao.selectPermitAuthority(roleId);
        return new HashSet<>(perms);
    }

    /**
     * 查列表
     *
     * @return list
     */
    public List<Permit> queryList() {
        return permitDao.selectList();
    }
}

